package cn.hnu.config;

import cn.hnu.domain.Users;
import cn.hnu.mapper.UserMapper;
import cn.hnu.utils.JwtUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpStatus;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsConfigurationSource;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.servlet.handler.HandlerMappingIntrospector;

import java.util.List;

/**
 * Spring Security 配置类
 */
@Configuration
@EnableWebSecurity
public class SecurityConfig {

    // 1. 手动注册 mvcHandlerMappingIntrospector 到根容器（解决 Security 依赖）
    @Bean
    public HandlerMappingIntrospector mvcHandlerMappingIntrospector() {
        return new HandlerMappingIntrospector();
    }

    // 2. 注册 BCryptPasswordEncoder（根容器的 Bean，供 UsersServiceImpl 注入）
    @Bean
    public BCryptPasswordEncoder bCryptPasswordEncoder() {
        return new BCryptPasswordEncoder();
    }

    // 安全过滤链配置
    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http
                .authorizeHttpRequests(authz -> authz
                        // 静态资源允许匿名访问
                        .requestMatchers("/css/**", "/js/**", "/images/**", "/webjars/**").permitAll()
                        // 认证处理接口允许匿名访问
                        .requestMatchers("/auth/**").permitAll()

                        // 按角色进行权限控制
                        .requestMatchers("/admin/**").hasRole("ADMIN")
                        .requestMatchers("/teacher/**").hasRole("TEACHER")
                        .requestMatchers("/student/**").hasRole("STUDENT")


                        // 其他所有请求都需要认证
                        .anyRequest().authenticated()
                )
                .formLogin(form -> form
                        .loginProcessingUrl("/auth/login") // 登录处理URL
                        .successHandler(authenticationSuccessHandler())
                        .failureHandler(authenticationFailureHandler())
                        .permitAll()
                )
                .logout(logout -> logout
                        .logoutUrl("/auth/logout") // 退出登录URL
                        .logoutSuccessHandler(logoutSuccessHandler())
                        .invalidateHttpSession(true) // 使Session失效
                        .deleteCookies("JSESSIONID") // 删除Cookie
                        .clearAuthentication(true) // 清除认证信息
                        .permitAll()
                )
                .sessionManagement(session -> session
                        .maximumSessions(1) // 最大会话数
                        .maxSessionsPreventsLogin(false) // false表示允许新登录踢掉旧登录
                )
                .csrf(csrf -> csrf.disable()); // 暂时禁用CSRF，方便API测试

        return http.build();
    }


    @Autowired
    private UserMapper userMapper;


    // 认证成功处理器（返回JSON和JWT）
    private AuthenticationSuccessHandler authenticationSuccessHandler() {
        return (request, response, authentication) -> {
            // 从认证信息中获取用户详情
            UserDetails userDetails = (UserDetails) authentication.getPrincipal();

            // 从UserDetails中提取用户信息
            String username = userDetails.getUsername();
            // 根据用户名获取用户对象
            Users users = userMapper.findByUsername(username);
            // 使用您的JWT工具类生成token
            String token = JwtUtils.sign(users.getId(), username, users.getRoleId());

            // 构建响应
            response.setContentType("application/json;charset=UTF-8");
            response.getWriter().write("{\n" +
                    "  \"success\": true,\n" +
                    "  \"message\": \"登录成功\",\n" +
                    "  \"data\": {\n" +
                    "    \"token\": \"" + token + "\",\n" +
                    "    \"userId\": " + users.getId() + ",\n" +
                    "    \"username\": \"" + username + "\",\n" +
                    "    \"roleId\": " + users.getRoleId() + "\n" +
                    "  }\n" +
                    "}");
        };
    }







    // 认证失败处理器（返回JSON）
    private AuthenticationFailureHandler authenticationFailureHandler() {
        return (request, response, exception) -> {
            response.setStatus(HttpStatus.UNAUTHORIZED.value());
            response.setContentType("application/json;charset=UTF-8");
            response.getWriter().write("{\"success\": false, \"message\": \"登录失败: " + exception.getMessage() + "\"}");
        };
    }

    // 退出成功处理器（返回JSON）
    private LogoutSuccessHandler logoutSuccessHandler() {
        return (request, response, authentication) -> {
            response.setContentType("application/json;charset=UTF-8");
            response.getWriter().write("{\"success\": true, \"message\": \"退出成功\"}");
        };
    }

    // CORS配置（允许前端跨域访问）
    @Bean
    public CorsConfigurationSource corsConfigurationSource() {
        CorsConfiguration configuration = new CorsConfiguration();
        configuration.setAllowedOriginPatterns(List.of("*")); // 允许所有源，生产环境应指定具体域名
        configuration.setAllowedMethods(List.of("GET", "POST", "PUT", "DELETE", "OPTIONS"));
        configuration.setAllowedHeaders(List.of("*"));
        configuration.setAllowCredentials(true);

        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", configuration);
        return source;
    }
}